package systemFunctionality;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Random;

import systemClasses.Item;
import systemClasses.Message;
import systemClasses.User;

/**
 * Classe que possui todas as funcionalidades do sistema.
 * 
 * @author Laércio Vitorino
 *
 */

public class Functionalities {
	
	private static ArrayList<User> registeredUsers;
	private ArrayList<Item> registeredItems;
	private ArrayList<Item> borrowedItems;
	private ArrayList<Message> allMessages;
	private GregorianCalendar currentDate;
	private ArrayList<String> allLoanRequisitions;
	private ArrayList<User> reputationSort;
	private ArrayList<User> usersRanking;
	private ArrayList<String[]> allHistoric;
	
	/**
	 * Construtor do sistema.
	 */
	public Functionalities(){
		registeredUsers = new ArrayList<User>();
		registeredItems = new ArrayList<Item>();
		borrowedItems = new ArrayList<Item>();
		allMessages = new ArrayList<Message>();
		currentDate = new GregorianCalendar();
		allLoanRequisitions = new ArrayList<String>();
		reputationSort = new ArrayList<User>();
		usersRanking = new ArrayList<User>();
		allHistoric = new ArrayList<String[]>();
	}
	
	/**
	 * Cria um usuário no sistema.
	 * 
	 * @param login
	 * 			O login do usuário.
	 * @param name
	 * 			O nome do usuário.
	 * @param address
	 * 			O endereço do usuário.
	 * @throws Exception
	 * 			Lança uma exceção caso um dos parâmetros seja nulo ou vazio.
	 */
	public void createUser(String login, String name, String address) throws Exception{
		for(User user : registeredUsers){
			if(user.getLogin().equals(login)){
				throw new Exception("Já existe um usuário com este login");
			}
		}
		
		registeredUsers.add(new User(login, name, address));
	}
	
	/**
	 * Checa se um usuário existe no sistema.
	 * 
	 * @param login
	 * 			O login do usuário.
	 * @throws Exception
	 * 			Lança uma exceção caso o usuário não exista no sistema.
	 */
	public static void checkNoUser(String login) throws Exception{
		int countNoUser = 0;
		
		for(User user : registeredUsers){
			if(!user.getLogin().equals(login)){
				countNoUser += 1;
			}
		}
		
		if (countNoUser == registeredUsers.size())
			throw new Exception("Usuário inexistente");
	}
	
	/**
	 * Checa se um dado login é válido.
	 * 
	 * @param login
	 * 			O login a ser verificado.
	 * @throws Exception
	 * 			Lança uma exceção caso o login seja inválido.
	 */
	public static void checkValidLogin(String login) throws Exception{
		if(login == null || login.equals(""))
			throw new Exception("Login inválido");
	}
	
	/**
	 * Abre uma sessão para um usuário do sistema.
	 * 
	 * @param login
	 * 			O login do usuário necessário para abrir a sessão. 
	 * @return
	 * 			O id(um identificador válido) para a sessão aberta.
	 * @throws Exception
	 * 			Lança uma exceção caso o usuário não exista no sistema.
	 */
	public static String openUserSession(String login) throws Exception{
		checkValidLogin(login);
		
		String idSession = "";
		
		for(User user : registeredUsers){
			if(user.getLogin().equals(login)){
				idSession = String.valueOf(Math.abs(new Random().nextInt()));
				user.setID(idSession);
				return idSession;
			}
		}
		
		throw new Exception("Usuário inexistente");
	}
	
	/**
	 * Checa a se a sessão do usuário é válida, caso contrário gera uma sessão válida.
	 * 
	 * @param user
	 * 			O usuário a qual a sessão será checada.
	 * @return
	 * 			O id da sessão válida.
	 * @throws Exception
	 * 			Lança uma exceção caso o usuário não exista no sistema.
	 */
	public static String checkUserSession(User user) throws Exception {
		String idSession = "";
		
		if(user.getID() == null || user.getID().equals("")){
			idSession = openUserSession(user.getLogin());
		}
		else{
			idSession = user.getID();
		}
		
		return idSession;
	}
	
	/**
	 * Checa se o id da sessão é válido.
	 * 
	 * @param idSession
	 * 			O id da sessão a ser checada.
	 * @throws Exception
	 * 			Lança uma exceção informando se a sessão é inválida ou inexistente.
	 */
	public static void checkValidIdSession(String idSession) throws Exception{
		if(idSession == null || idSession.equals(""))
			throw new Exception("Sessão inválida");
		
		if (!idSession.matches("^[0-9]*$"))
			throw new Exception("Sessão inexistente");
	}
	
	/**
	 * Obtém um dos atributos do usuário, que pode ser: nome ou endereço.
	 * 
	 * @param login
	 * 			O login do usuário.
	 * @param attribute
	 * 			O atributo a ser obtido do usuário.
	 * @return
	 * 			O atributo do usuário. 
	 * @throws Exception
	 * 			Lança uma exceção caso o atributo não exista ou um dos parâmetros de entrada seja inválido.
	 */
	public String getUserAttribute(String login, String attribute) throws Exception{
		if(attribute == null || attribute.equals(""))
			throw new Exception("Atributo inválido");
		
		String userAttribute = "";
		
		if(openUserSession(login) != null){
			for(User user : registeredUsers){
				if(user.getLogin().equals(login)){
					if(attribute.equals("nome"))
						userAttribute = user.getName();
					else if(attribute.equals("endereco"))
						userAttribute = user.getAddress();
					else
						throw new Exception("Atributo inexistente");
				}
			}
		}
		
		return userAttribute;
	}
	
	/**
	 * Cadastra itens no sistema.
	 * 
	 * @param idSession
	 * 			O id da sessão do usuário.
	 * @param name
	 * 			O nome do item a ser cadastrado no sistema.
	 * @param description
	 * 			A descrição do item a ser cadastrado no sistema.
	 * @param category
	 * 			A categoria do item a ser cadastrado no sistema, a qual pode ser: Filme, Livro ou Jogo.
	 * @return
	 * 			Uma id(identificação válida) do item cadastrado no sistema.
	 * @throws Exception
	 * 			Lança uma exceção se o identificador do item é inválido ou um dos parâmetros de entrada seja inválido.
	 */
	public String registerItems(String idSession, String name, String description, String category) throws Exception{
		checkValidIdSession(idSession);
		
		if(category == null || category.equals(""))
			throw new Exception("Categoria inválida");
		
		if(!category.toLowerCase().equals("livro") && !category.toLowerCase().equals("filme") && !category.toLowerCase().equals("jogo"))
			throw new Exception("Categoria inexistente");
		
		String itemID = "";
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				Item newItem = new Item(name, description, category) ;
				
				if(!user.getMyRegisteredItems().contains(newItem)){
					itemID = String.valueOf(Math.abs(new Random().nextInt()));
					newItem.setID(itemID);
					newItem.setOwner(user);
					user.registerMyItems(newItem);
					registeredItems.add(newItem);
					String historicMessage = user.getName() + " cadastrou " + newItem.getName();
					user.addToMyHistoric(historicMessage);
					String[] historic = {historicMessage, user.getLogin()};
					allHistoric.add(historic);
					return itemID;
				}
			}
		}
		
		throw new Exception("Identificador do item é inválido");
	}
	
	/**
	 * Obtém um atributo do item.
	 * 
	 * @param idItem
	 * 			O id do item do qual o atributo será obtido.
	 * @param attribute
	 * 			O atributo a ser obtido do item.
	 * @return
	 * 			O atributo do item.
	 * @throws Exception
	 * 			Lança uma exceção se o atributo passado como parâmetro for inexistente ou um dos parâmetros de entrada seja inválido.
	 */
	public String getItemAttribute(String idItem, String attribute) throws Exception{
		if(idItem == null || idItem.equals(""))
			throw new Exception("Identificador do item é inválido");
		
		if (!idItem.matches("^[0-9]*$"))
			throw new Exception("Item inexistente");
		
		if(attribute == null || attribute.equals(""))
			throw new Exception("Atributo inválido");
		
		String itemAttribute = "";
		
		for(Item item : registeredItems){
			if(item.getID().equals(idItem)){
				if(attribute.equals("nome"))
					itemAttribute = item.getName();
				else if(attribute.equals("descricao"))
					itemAttribute = item.getDescription();
				else if(attribute.equals("categoria"))
					itemAttribute = item.getCategory();
				else
					throw new Exception("Atributo inexistente");
			}
		}
		
		return itemAttribute;
	}
	
	/**
	 * Localiza um usuário no sistema.
	 * 
	 * @param idSession
	 * 			O id da sessão do usuário.
	 * @param keyWord
	 * 			Uma palavra-chave utilizada para localizar um determinado usuário no sistema.
	 * @param attribute
	 * 			Um atributo utilizado para localizar um determinado usuário no sistema, o qual pode ser: nome ou endereço.
	 * @return
	 * 			Informações do usuário baseadas nos parâmetros passados como entrada.
	 * @throws Exception
	 * 			Lança uma exceção caso o usuário não seja localizado ou então se um dos parâmetros de entrada seja inválido.
	 */
	public String findUser(String idSession, String keyWord, String attribute) throws Exception{
		checkValidIdSession(idSession);
		
		if(keyWord == null || keyWord.equals(""))
			throw new Exception("Palavra-chave inválida");
		
		if(attribute == null || attribute.equals(""))
			throw new Exception("Atributo inválido");
		
		if(!attribute.equals("nome") && !attribute.equals("endereco"))
			throw new Exception("Atributo inexistente");
		
		String userInformation = "";
		
		for(User user: registeredUsers){
			if(!checkUserSession(user).equals(idSession)){
				if(attribute.equals("nome")){
					if(user.getLogin().equals(keyWord.toLowerCase()) && !user.getID().equals(idSession))
						userInformation += user.getName() + " - " + user.getAddress() + "; ";
					
				}
				else if(attribute.equals("endereco")){
					if(user.getAddress().split(", ")[0].equals(keyWord) && !user.getID().equals(idSession))
						userInformation += user.getName() + " - " + user.getAddress() + "; ";
				}
			}
		}
		
		if(userInformation.equals(""))
			return "Nenhum usuário encontrado";
		
		return userInformation = userInformation.substring(0, userInformation.length() - 2);
	}
	
	/**
	 * Obtém pedidos de amizade.
	 * 
	 * @param idSession
	 * 			O id da sessão do usuário.
	 * @return
	 * 			Os amigos que requisitaram amizade ao usuário logado no sistema.
	 * @throws Exception
	 * 			Lança uma exceção caso a requisição de amizade seja inválida.
	 */
	public String getFriendshipRequests(String idSession) throws Exception{
		checkValidIdSession(idSession);
		
		String friendship = "";
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				if(user.getFriendshipRequests().size() != 0){
					for(int i = 0; i < user.getFriendshipRequests().size(); i++){
						friendship += user.getFriendshipRequests().get(i).getLogin() + "; ";
					}
				}
			}
			
			if(friendship.equals(""))
				return "Não há requisições";
			
			else
				return friendship = friendship.substring(0, friendship.length() - 2);
		}
		
		throw new Exception("Requisição inválida");
	}
	
	/**
	 * Requisita amizade a um usuário do sistema.
	 * 
	 * @param idSession
	 * 			O id da sessão do usuário.
	 * @param login
	 * 			O login do usuário o qual se está requisitando amizade.
	 * @throws Exception
	 * 			Lança uma exceção caso os usuários já sejam amigos ou se um dos parâmetros de entrada seja inválido.
	 */
	public void requestFriendship(String idSession, String login) throws Exception{
		checkValidIdSession(idSession);
		checkValidLogin(login);
		checkNoUser(login);
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				for(User anotherUser : registeredUsers){
					if(login.equals(anotherUser.getLogin())){
						if(!anotherUser.getFriends().contains(user))
							anotherUser.addRequestFriendship(user);
						else
							throw new Exception("Os usuários já são amigos");
					}
				}
			}
		}
	}
	
	/**
	 * Checa se usuário do sistema são amigos.
	 * 
	 * @param idSession
	 * 			O id da sessão do usuário que está logado no sistema.
	 * @param login
	 * 			O login de um outro usuário do sistema.
	 * @return
	 * 			True caso os usuários são amigos, false caso contrário.
	 * @throws Exception
	 * 			Lança uma exceção caso um dos parâmetros de entrada seja inválido.
	 */
	public boolean isFriend(String idSession, String login) throws Exception{
		checkValidIdSession(idSession);
		checkValidLogin(login);
		checkNoUser(login);
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				for(User friend : user.getFriends()){
					if(friend.getLogin().equals(login)){
						return true;
					}
				}
			}
		}
		
		return false;
	}
	
	/**
	 * Aprova o pedido de amizade de um usuário do sistema.
	 * 
	 * @param idSession
	 * 			O id da sessão do usuário logado no sistema.
	 * @param login
	 * 			O login do usuário que requisitou amizade.
	 * @throws Exception
	 * 			Lança uma exceção caso um dos parâmtros de entrada seja inválido, ou caso a requisição de
	 * 			amizade seja inexistente ou caso os usuário já sejam amigos.
	 */
	public void approveFriendship(String idSession, String login) throws Exception{
		checkValidIdSession(idSession);
		checkValidLogin(login);
		checkNoUser(login);
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				for(User anotherUser : registeredUsers){
					if(anotherUser.getLogin().equals(login)){
						if(!user.getFriends().contains(anotherUser)){
							if(user.getFriendshipRequests().contains(anotherUser)){
								user.addFriend(anotherUser);
								anotherUser.addFriend(user);
								user.getFriendshipRequests().remove(anotherUser);
								String historicMessage1 = user.getName() + " e " + anotherUser.getName() + " são amigos agora";
								String historicMessage2 = anotherUser.getName() + " e " + user.getName() + " são amigos agora";
								user.addToMyHistoric(historicMessage1);
								anotherUser.addToMyHistoric(historicMessage2);
								String[] historic1 = {historicMessage1, user.getLogin()};
								String[] historic2 = {historicMessage2, anotherUser.getLogin()};
								allHistoric.add(0, historic1);
								allHistoric.add(0, historic2);
							}
							else
								throw new Exception("Requisição de amizade inexistente");
						}
						else
							throw new Exception("Os usuários já são amigos");
					}
				}
			}
		}
	}
	
	/**
	 * Obtém os amigos de um determinado usuário.
	 * 
	 * @param idSession
	 * 			O id da sessão do usuário logado no sistema.
	 * @return
	 * 			Os amigos do usuário logado.
	 * @throws Exception
	 * 			Lança uma exceção caso a o id da sessão seja inválido.
	 */
	public String getFriends(String idSession) throws Exception{
		checkValidIdSession(idSession);
		
		String friends = "";
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				if(user.getFriends().size() == 0)
					return "O usuário não possui amigos";
				else{
					for(User friend : user.getFriends()){
						friends += friend.getLogin() + "; ";
					}
				}
			}	
		}
		
		return friends = friends.substring(0, friends.length() - 2);
	}
	
	/**
	 * Obtém os amigos de um amigo do usuário logado no sistema.
	 * 
	 * @param idSession
	 * 			O id do usuário logado no sistema.
	 * @param login
	 * 			O login do amigo do usuário logado no sistema.
	 * @return
	 * 			Os amigos do amigo do usuário logado no sistema.
	 * @throws Exception
	 * 			Lança uma exceção caso um dos parâmetros de entrada seja inválido.
	 */
	public String getFriends(String idSession, String login) throws Exception{
		checkValidIdSession(idSession);
		checkValidLogin(login);
		checkNoUser(login);
		
		String friends = "";
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				for(User anotherUser : registeredUsers){
					if(anotherUser.getLogin().equals(login)){
						for(User friendsOfFriend : anotherUser.getFriends())
							friends += friendsOfFriend.getLogin() + "; ";
					}
				}
			}
		}
		
		if(friends.equals("")){
			return "O usuário não possui amigos";
		}
		else{
			return friends = friends.substring(0, friends.length() - 2);
		}
	}
	
	/**
	 * Obtém itens cadastrados no sistema.
	 * 
	 * @param idSession
	 * 			O id da sessão de um usuário logado no sistema.
	 * @return
	 * 			Os itens do usuário logado no sistema.
	 * @throws Exception
	 * 			Lança uma exceção caso o id da sessão seja inválido.
	 */
	public String getItems(String idSession) throws Exception{
		checkValidIdSession(idSession);
		
		String userItem = "";
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				if(user.getMyRegisteredItems().size() == 0)
					return "O usuário não possui itens cadastrados";
				else{
					for(Item item : user.getMyRegisteredItems()){
						userItem += item.getName() + "; ";
					}
				}
			}
		}
		
		return userItem = userItem.substring(0, userItem.length() - 2);
	}
	
	/**
	 * Obtém os itens de um amigo do usuário logado no sistema.
	 * 
	 * @param idSession
	 * 			O id da sessão do usuário logado no sistema.
	 * @param login
	 * 			O login do amigo do usuário logado no sistema.
	 * @return
	 * 			O itens do amigo do usuário logado no sistema.
	 * @throws Exception
	 * 			Lança uma exceção caso um dos parâmetros de entrada seja inválido ou caso o usuário não
	 * 			tenha permissão para visualizar os itens.
	 */
	public String getItems(String idSession, String login) throws Exception{
		checkValidIdSession(idSession);
		checkValidLogin(login);
		checkNoUser(login);
		
		String userItem = "";
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				for(User friend : user.getFriends()){
					if(friend.getLogin().equals(login)){
						if(friend.getMyRegisteredItems().size() == 0)
							return "O usuário não possui itens cadastrados";
						else{
							for(Item item : friend.getMyRegisteredItems()){
								userItem += item.getName() + "; ";
							}
						}
					}
					else
						throw new Exception("O usuário não tem permissão para visualizar estes itens");
				}
			}
		}
		
		return userItem = userItem.substring(0, userItem.length() - 2);
	}
	
	/**
	 * Obtém os empréstimos de um usuário.
	 * 
	 * @param idSession
	 * 			O id da sessão do usuário logado no sistema.
	 * @param type
	 * 			A condição do usuário nos empréstimos, que pode ser: emprestador, beneficiado ou também
	 * 			podendo obter todos os empréstimos do sistema.
	 * @return
	 * 			Os empréstimos no sistema com a devida relação entre os usuários.
	 * @throws Exception
	 * 			Lança uma exceção caso um dos parâmetros de entrada seja inválido.
	 */
	public String getLoans(String idSession, String type) throws Exception{
		checkValidIdSession(idSession);
		
		if(type == null || type.equals(""))
			throw new Exception("Tipo inválido");
		
		if(!type.equals("emprestador") && !type.equals("beneficiado") && !type.equals("todos"))
			throw new Exception("Tipo inexistente");
		
		String loans = "";
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				if(type.equals("emprestador")){
					if(user.getMyBorrowedItems().size() == 0)
						return "Não há empréstimos deste tipo";
					else{
						for(Item item : user.getMyBorrowedItems()){
							loans += item.getOwner().getLogin() + "-" + item.getBorrower().getLogin() + ":" + item.getName() + ":" + item.getStatus() + "; ";
						}
					}
				}
				else if(type.equals("beneficiado")){
					if(user.getMyItemsBorrowed().size() == 0)
						return "Não há empréstimos deste tipo";
					else{
						for(Item item : user.getMyItemsBorrowed()){
							loans += item.getOwner().getLogin() + "-" + item.getBorrower().getLogin() + ":" + item.getName() + ":" + item.getStatus() + "; ";
						}
					}
				}
				else{
					if(borrowedItems.size() == 0)
						return "Não há empréstimos deste tipo";
					else{
						for(Item item : borrowedItems){
							if(item.getOwner().equals(user)){
								loans += item.getOwner().getLogin() + "-" + item.getBorrower().getLogin() + ":" + item.getName() + ":" + item.getStatus() + "; ";
								
								for(Item otherItems : borrowedItems){
									if(otherItems.getBorrower().equals(user))
										loans += otherItems.getOwner().getLogin() + "-" + otherItems.getBorrower().getLogin() + ":" + otherItems.getName() + ":" + otherItems.getStatus() + "; ";
								}
							}
						}
						if(loans.equals("")){
							for(Item items : borrowedItems){
								if(items.getBorrower().equals(user))
									loans += items.getOwner().getLogin() + "-" + items.getBorrower().getLogin() + ":" + items.getName() + ":" + items.getStatus() + "; ";
							}
						}
					}
				}
			}
		}
		
		return loans = loans.substring(0, loans.length() - 2);
	}
	
	/**
	 * Realiza requisições de empréstimo de itens entre os usuários do sistema.
	 * 
	 * @param idSession
	 * 			O id da sessão do usuário logado no sistema.
	 * @param idItem
	 * 			O id do item a ser requisitado.
	 * @param duration
	 * 			A duração, em dias, do empréstimo.
	 * @return
	 * 			O id(identificação válida) do item requisitado.
	 * @throws Exception
	 * 			Lança uma exceção caso um dos parâmetros de entrada seja inválido, ou caso a requisição
	 * 			de empréstimo de um determinado item já foi feita, ou caso o usuário não tenha permissão
	 * 			para requisitar o empréstimo de um determinado item.
	 */
	public String loanRequests(String idSession, String idItem, int duration) throws Exception{
		checkValidIdSession(idSession);
		
		if(idItem == null || idItem.equals(""))
			throw new Exception("Identificador do item é inválido");
		
		if(duration <= 0)
			throw new Exception("Duracao inválida");
		
		String idRequisition = "";
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				for(Item item : registeredItems){
					if(item.getID().equals(idItem)){
						if(item.getOwner().getFriends().contains(user)){
							if(!item.getOwner().getMyRequestedItems().contains(item)){
								idRequisition = String.valueOf(Math.abs(new Random().nextInt()));
								allLoanRequisitions.add(idRequisition);
								item.setIdRequisition(idRequisition);
								item.setRequisitionDuration(duration);
								item.setBorrower(user);
								item.getOwner().addMyRequestedItems(item);
								
								String subject = "Empréstimo do item " + item.getName() + " a " + user.getName();
								String message = user.getName() + " solicitou o empréstimo do item " + item.getName();
								Message newMessage = new Message(item.getOwner().getLogin(), subject, message);
								item.getOwner().addMyNegotiationMessages(newMessage);
								item.getOwner().addMyAllMessages(newMessage);
								user.addMyNegotiationMessages(newMessage);
								user.addMyAllMessages(newMessage);
								allMessages.add(newMessage);
								newMessage.setSender(user);
								String messageTopicId = String.valueOf(Math.abs(new Random().nextInt()));
								newMessage.setID(messageTopicId);
								
								return idRequisition;
							}
							else
								throw new Exception("Requisição já solicitada");
						}
						else
							throw new Exception("O usuário não tem permissão para requisitar o empréstimo deste item");
					}
				}
			}
		}
		
		throw new Exception("Item inexistente");
	}
	
	/**
	 * Aprova o empréstimo de itens do sistema.
	 * 
	 * @param idSession
	 * 			O id da sessão do usuário logado no sistema.
	 * @param idLoanRequisition
	 * 			O id da requisição feita do item.
	 * @return
	 * 			O id(identificação válida) do empréstimo do item.
	 * @throws Exception
	 * 			Lança uma exceção caso um dos parâmetros de entrada seja inválido, ou caso o empréstimo de
	 * 			um determinado item já tenha sido aprovado, ou caso a requisição do empréstimo seja
	 * 			inexistente ou caso o empréstimo não possa ser aprovado pelo usuário que está logado.
	 */
	public String approveLoans(String idSession, String idLoanRequisition) throws Exception{
		checkValidIdSession(idSession);
		
		if(idLoanRequisition == null || idLoanRequisition.equals(""))
			throw new Exception("Identificador da requisição de empréstimo é inválido");
		
		if (!idLoanRequisition.matches("^[0-9]*$"))
			throw new Exception("Requisição de empréstimo inexistente");
		
		String idLoan = "";
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				for(Item item : user.getMyRequestedItems()){
					if(item.getIdRequisition().equals(idLoanRequisition)){
						if(allLoanRequisitions.contains(idLoanRequisition)){
							if(!user.getMyBorrowedItems().contains(item)){
								idLoan = String.valueOf(Math.abs(new Random().nextInt()));
								item.setIDLoan(idLoan);
								item.setStatus("Andamento");
								user.addMyBorrowedItems(item);
								item.getBorrower().addMyItemsBorrowed(item);
								borrowedItems.add(item);
								GregorianCalendar dateOfLoan = new GregorianCalendar();
								dateOfLoan.set(Calendar.DAY_OF_MONTH, dateOfLoan.get(5) + item.getRequisitionDuration());
								item.setDateOfLoan(dateOfLoan);
								user.getMyDesiredItems().remove(item);
								String historicMessage = user.getName() + " emprestou " + item.getName() + " a " + item.getBorrower().getName();
								user.addToMyHistoric(historicMessage);
								String[] historic = {historicMessage, user.getLogin()};
								allHistoric.add(0, historic);
							}
							else{
								throw new Exception("Empréstimo já aprovado");
							}
						}
						else{
							throw new Exception("Requisição de empréstimo inexistente");
						}
					}
					else{
						throw new Exception("O empréstimo só pode ser aprovado pelo dono do item");
					}
				}
			}
		}
		return idLoan;
	}
	
	/**
	 * Retorna um item para o seu dono.
	 * 
	 * @param idSession
	 * 			O id da sessão do usuário logado no sistema.
	 * @param idLoan
	 * 			O id do empréstimo do item.
	 * @throws Exception
	 * 			Lança uma exceção caso um dos parâmetros de entrada seja inválido, ou caso o item já tenha
	 * 			sido devolvido ou caso o item não possa ser devolvido pelo usuário logado no sistema.
	 */
	public void returnItem(String idSession, String idLoan) throws Exception{
		checkValidIdSession(idSession);
		
		if(idLoan == null || idLoan.equals(""))
			throw new Exception("Identificador do empréstimo é inválido");
		
		if (!idLoan.matches("^[0-9]*$"))
			throw new Exception("Empréstimo inexistente");
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				for(Item item : borrowedItems){
					if(item.getIdLoan().equals(idLoan)){
						if(item.getBorrower().equals(user)){
							if(user.getMyItemsBorrowed().contains(item)){
								item.getOwner().addMyReturnedItems(item);
								user.getMyItemsBorrowed().remove(item);
								break;
							}
							else
								throw new Exception("Item já devolvido");
						}
						else
							throw new Exception("O item só pode ser devolvido pelo usuário beneficiado");
					}
				}
			}
		}
	}
	
	/**
	 * Confirma o término de um empréstimo de um item.
	 * 
	 * @param idSession
	 * 			O id da sessão do usuário logado no sistema.
	 * @param idLoan
	 * 			O id do empréstimo de um item.
	 * @throws Exception
	 * 			Lança uma exceção caso um dos parâmetros de entrada seja inválido, ou caso o término do
	 * 			empréstimo já tenha sido confirmado ou caso o término do empréstimo não possa ser
	 * 			confirmado pelo usuário logado no sistema.
	 */
	public void confirmsEndLoan(String idSession, String idLoan) throws Exception{
		checkValidIdSession(idSession);
		
		if(idLoan == null || idLoan.equals("")){
			throw new Exception("Identificador do empréstimo é inválido");
		}
		
		if (!idLoan.matches("^[0-9]*$")){
			throw new Exception("Empréstimo inexistente");
		}
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				for(Item item : borrowedItems){
					if(item.getIdLoan().equals(idLoan)){
						if(user.getMyRegisteredItems().contains(item)){
							if(!item.getStatus().equals("Cancelado")){
								if(item.getStatus().equals("Andamento")){
									item.setStatus("Completado");
									user.getMyBorrowedItems().remove(item);
									user.getMyRequestedItems().remove(item);
									String historicMessage = user.getName() + " confirmou o término do empréstimo do item " + item.getName();
									user.addToMyHistoric(historicMessage);
									String[] historic = {historicMessage, user.getLogin()};
									allHistoric.add(0, historic);
										
									if(user.getMyDesiredItems().size() != 0){
										String subject = "O item " + item.getName() + " do usuário " + item.getOwner().getName() + " está disponível";
										String message = "Agora você pode requisitar o empréstimo do " + item.getName() + ".";
										Message newMessage = new Message(user.getName(), subject, message);
											
										for(User friends : user.getMyDesiredItems().get(item)){
											friends.addMyOffTopicMessages(newMessage);
											friends.addMyAllMessages(newMessage);
										}
									}
									break;
								}
								else{
									throw new Exception("Término do empréstimo já confirmado");
								}
							}
						}
						else{
							throw new Exception("O término do empréstimo só pode ser confirmado pelo dono do item");
						}
					}
				}
				user.setReputation(calculateReputation(user));
			}
		}
	}
	
	/**
	 * Envia uma mensagem a um usuário do sistema.
	 * 
	 * @param idSession
	 * 			O id da sessão do usuário logado no sistema.
	 * @param receiver
	 * 			O destinatário da mensagem.
	 * @param subject
	 * 			O assunto da mensagem.
	 * @param message
	 * 			A mensagem a ser enviada.
	 * @return
	 * 			O id(identificado válido) do tópico da mensagem enviada.
	 * @throws Exception
	 * 			Lança uma exceção caso um dos parâmetros de entrada seja inválido.
	 */
	public String sendMessage(String idSession, String receiver, String subject, String message) throws Exception{
		checkValidIdSession(idSession);
		
		if(receiver == null || receiver.equals(""))
			throw new Exception("Destinatário inválido");
		
		int countNoReceiver = 0;

		for (User user : registeredUsers) {
			if (!user.getLogin().equals(receiver))
				countNoReceiver += 1;
		}

		if (countNoReceiver == registeredUsers.size())
			throw new Exception("Destinatário inexistente");
		
		if(subject == null || subject.equals(""))
			throw new Exception("Assunto inválido");
		
		if(message == null || message.equals(""))
			throw new Exception("Mensagem inválida");
		
		String messageTopicId = "";
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				for(User friend : user.getFriends()){
					if(friend.getLogin().equals(receiver)){
						Message newMessage = new Message(receiver, subject, message);
						user.addMyOffTopicMessages(newMessage);
						user.addMyAllMessages(newMessage);
						friend.addMyOffTopicMessages(newMessage);
						friend.addMyAllMessages(newMessage);
						allMessages.add(newMessage);
						newMessage.setSender(user);
						messageTopicId = String.valueOf(Math.abs(new Random().nextInt()));
						newMessage.setID(messageTopicId);
						
						for(Message messages : allMessages){
							if(messages.getSubject().equals(newMessage.getSubject())){
								messageTopicId = messages.getID();
								newMessage.setID(messageTopicId);
							}
						}
					}
					else{
						countNoReceiver += 1;
					}
				}
			}
		}
		
		return messageTopicId;
	}
	
	/**
	 * Ler tópicos de mensagens enviadas entre os usuários do sistema.
	 * 
	 * @param idSession
	 * 			O id da sessão do usuário logado no sistema.
	 * @param type
	 * 			O tipo de tópico da mensagem, que pode ser: negocição, off-topic ou todos.
	 * @return
	 * 			Os tópicos das mensagens enviadas entre usuários do sistema.
	 * @throws Exception
	 * 			Lança uma exceção caso um dos parâmetros de entrada seja inválido.
	 */
	public String readTopics(String idSession, String type) throws Exception{
		checkValidIdSession(idSession);
		
		if(type == null || type.equals(""))
			throw new Exception("Tipo inválido");
		
		if(!type.equals("negociacao") && !type.equals("offtopic") && !type.equals("todos"))
			throw new Exception("Tipo inexistente");
		
		String topic = "";
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				if(type.equals("negociacao")){
					if(user.getMyNegotiationMessages().size() == 0)
						return "Não há tópicos criados";
					else{
						for(Message messages : user.getMyNegotiationMessages()){
							if(!topic.contains(messages.getSubject())){
								topic += messages.getSubject() + "; ";
							}
						}
					}
				}
				else if(type.equals("offtopic")){
					if(user.getMyOffTopicMessages().size() == 0){
						return "Não há tópicos criados";
					}
					else{
						for(Message messages : user.getMyOffTopicMessages()){
							if(!topic.contains(messages.getSubject())){
								topic = messages.getSubject() + "; " + topic;
							}
						}
					}
				}
				else{
					if(user.getMyAllMessages().size() == 0)
						return "Não há tópicos criados";
					else{
						for(Message messages : user.getMyAllMessages()){
							if(!topic.contains(messages.getSubject())){
								topic = messages.getSubject() + "; " + topic;
							}
						}
					}
				}
			}
		}
		
		return topic = topic.substring(0, topic.length() - 2);
	}
	
	/**
	 * Ler mensagens enviadas entre os usuários do sistema.
	 * 
	 * @param idSession
	 * 			O id da sessão do usuário logado no sistema.
	 * @param idTopic
	 * 			O id do tópico da(s) mensagem(ns) a serem lidas.
	 * @return
	 * 			A mensagens lidas de um determinado tópico.
	 * @throws Exception
	 * 			Lança uma exceção caso um dos parâmetros de entrada seja inválido ou caso o usuário logado
	 * 			não tenha permissão de visualizar as mensagens de um determinado tópico.
	 */
	public String readMessages(String idSession, String idTopic) throws Exception{
		checkValidIdSession(idSession);
		
		if(idTopic == null || idTopic.equals(""))
			throw new Exception("Identificador do tópico é inválido");
		
		if (!idTopic.matches("^[0-9]*$"))
			throw new Exception("Tópico inexistente");
		
		String readMessage = "";
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				for(Message message : user.getMyAllMessages()){
					if(message.getID().equals(idTopic)){
						readMessage += message.getMessage() + "; ";
					}
				}
			}
		}
		
		if(readMessage.equals(""))
			throw new Exception("O usuário não tem permissão para ler as mensagens deste tópico");
		
		return readMessage = readMessage.substring(0, readMessage.length() - 2);
	}
	
	/**
	 * Envia mensagens entre os usuários do sistema com relação a uma certa negocição de um item.
	 * 
	 * @param idSession
	 * 			O id da sessão do usuário logado no sistema.
	 * @param receiver
	 * 			O destinatário da mensagem.
	 * @param subject
	 * 			O assunto da mensagem.
	 * @param message
	 * 			A mensagem a ser enviada.
	 * @param idLoanRequisition
	 * 			O id da requisição do item.
	 * @return
	 * 			O id(identificador válido) do tópico da mensagem.
	 * @throws Exception
	 * 			Lança uma exceção caso um dos parâmetros de entrada seja inválido, ou caso o usuário logado
	 * 			não participa do empréstimo do item.
	 */
	public String sendMessage(String idSession, String receiver, String subject, String message, String idLoanRequisition) throws Exception{
		checkValidIdSession(idSession);
		
		if(receiver == null || receiver.equals(""))
			throw new Exception("Destinatário inválido");
		
		int countNoReceiver = 0;

		for(User user : registeredUsers){
			if(!user.getLogin().equals(receiver))
				countNoReceiver += 1;
		}
		

		if (countNoReceiver == registeredUsers.size())
			throw new Exception("Destinatário inexistente");
		
		if(subject == null || subject.equals(""))
			throw new Exception("Assunto inválido");
		
		if(message == null || message.equals(""))
			throw new Exception("Mensagem inválida");
		
		if(idLoanRequisition == null || idLoanRequisition.equals(""))
			throw new Exception("Identificador da requisição de empréstimo é inválido");
		
		if (!idLoanRequisition.matches("^[0-9]*$"))
			throw new Exception("Requisição de empréstimo inexistente");
		
		String messageTopicId = "";
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				for(User friend : user.getFriends()){
					if(friend.getLogin().equals(receiver)){
						for(Item item : user.getMyRequestedItems()){
							if(item.getIdRequisition().equals(idLoanRequisition)){
								Message newMessage = new Message(receiver, subject, message);
								user.addMyNegotiationMessages(newMessage);
								user.addMyAllMessages(newMessage);
								friend.addMyNegotiationMessages(newMessage);
								friend.addMyAllMessages(newMessage);
								allMessages.add(newMessage);
								newMessage.setSender(user);
								messageTopicId = String.valueOf(Math.abs(new Random().nextInt()));
								newMessage.setID(messageTopicId);
								
								for(Message messages : user.getMyNegotiationMessages()){
									if(messages.getSubject().equals(newMessage.getSubject())){
										messageTopicId = messages.getID();
										newMessage.setID(messageTopicId);
										return messageTopicId;
									}
								}
							}
						}
					}
				}
			}
		}
		throw new Exception("O usuário não participa deste empréstimo");
	}
	
	/**
	 * Requisita a devolução de algum item.
	 * 
	 * @param idSession
	 * 			O id da sessão do usuário logado no sistema.
	 * @param idLoan
	 * 			O id do empréstimo do item.
	 * @throws Exception
	 * 			Lança uma exceção caso um dos parâmetros de entrada seja inválido, ou caso o item já tenha
	 * 			sido devolvido ou caso o usuário logado não tenha permissão para requisitar a devolução do
	 * 			item.
	 */
	public void returnRequest(String idSession, String idLoan) throws Exception{
		checkValidIdSession(idSession);
		
		if(idLoan == null || idLoan.equals(""))
			throw new Exception("Identificador do empréstimo é inválido");
		
		if (!idLoan.matches("^[0-9]*$"))
			throw new Exception("Empréstimo inexistente");
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				for(Item item : borrowedItems){
					if(item.getIdLoan().equals(idLoan)){
						if(user.getMyBorrowedItems().contains(item)){
							if(!user.getMyReturnedItems().contains(item)){
								
								GregorianCalendar requisitionDate = currentDate;
								
								if(requisitionDate.get(1) < item.getDateOfLoan().get(1))
									item.setStatus("Cancelado");
								else if(requisitionDate.get(1) == item.getDateOfLoan().get(1)){
									if(requisitionDate.get(2) < item.getDateOfLoan().get(2))
										item.setStatus("Cancelado");
									else if(requisitionDate.get(2) == item.getDateOfLoan().get(2)){
										if(requisitionDate.get(5) < item.getDateOfLoan().get(5)){
											item.setStatus("Cancelado");
										}
									}
								}
								
								user.addMyReturnRequests(item);
								
								if(item.getStatus().equals("Cancelado")){
									String subject = "Empréstimo do item " + item.getName() + " a " + item.getBorrower().getName();
									String message = user.getName() + " solicitou a devolução do item " + item.getName();
									Message newMessage = new Message(item.getBorrower().getLogin(), subject, message);
									user.addMyNegotiationMessages(newMessage);
									user.addMyAllMessages(newMessage);
									item.getBorrower().addMyNegotiationMessages(newMessage);
									item.getBorrower().addMyAllMessages(newMessage);
									allMessages.add(newMessage);
									newMessage.setSender(user);
									String messageTopicId = String.valueOf(Math.abs(new Random().nextInt()));
									newMessage.setID(messageTopicId);
									
									for(Message messages : user.getMyNegotiationMessages()){
										if(messages.getSubject().equals(newMessage.getSubject())){
											messageTopicId = messages.getID();
											newMessage.setID(messageTopicId);
										}
									}
								}
							}
							else
								throw new Exception("Item já devolvido");
						}
						else
							throw new Exception("O usuário não tem permissão para requisitar a devolução deste item");
					}
				}
			}
		}
	}
	
	/**
	 * Adiciona dias a requisição de empréstimo de um determinado item.
	 * 
	 * @param days
	 * 			A quantidade de dias a ser adicionado.
	 * @throws Exception
	 * 			Lança uma exceção caso a quantidade de dias seja menor ou igual a zero.
	 */
	public void addDays(int days) throws Exception{
		if(days <= 0)
			throw new Exception("Duração inválida");
		
		currentDate.set(Calendar.DAY_OF_MONTH, currentDate.get(5) + days);
	}
	
	/**
	 * Registra interesse em itens do sistema.
	 * 
	 * @param idSession
	 * 			O id do usuário logado no sistema.
	 * @param idItem
	 * 			O id do item o qual será registrado interesse.
	 * @throws Exception
	 * 			Lança uma exceção caso um dos parâmetros de entrada seja inválido ou caso o usuário logado já
	 * 			tenha registrado interesse no item especificado, ou caso o usuário logado não possa
	 * 			registrar interesse no item ou caso o item seja do próprio usuário logado no sistema.
	 */
	public void registerInterest(String idSession, String idItem) throws Exception{
		checkValidIdSession(idSession);
		
		if(idItem == null || idItem.equals(""))
			throw new Exception("Identificador do item é inválido");
		
		if (!idItem.matches("^[0-9]*$"))
			throw new Exception("Item inexistente");
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				for(Item item : registeredItems){
					if(item.getID().equals(idItem)){
						if(!item.getOwner().getName().equals(user.getName())){
							if(item.getOwner().getFriends().contains(user)){
								if(item.getOwner().getMyDesiredItems().size() == 0 || !item.getOwner().getMyDesiredItems().get(item).contains(user)){
									item.getOwner().addMyDesiredItems(item, user);
									String historicMessage = user.getName() + " tem interesse pelo item " + item.getName() + " de " + item.getOwner().getName();
									user.addToMyHistoric(historicMessage);
									String[] historic = {historicMessage, user.getLogin()};
									allHistoric.add(0, historic);
								}
								else{
									throw new Exception("O usuário já registrou interesse neste item");
								}
							}
							else{
								throw new Exception("O usuário não tem permissão para registrar interesse neste item");
							}
						}
						else{
							throw new Exception("O usuário não pode registrar interesse no próprio item");
						}
					}
				}
			}
		}
	}
	
	/**
	 * Pesquisa itens no sistema.
	 * 
	 * @param idSession
	 * 			O id da sessão do usuário logado no sistema.
	 * @param keyWord
	 * 			A palavra-chave a ser utilizada na pesquisa do item.
	 * @param attribute
	 * 			O atributo a ser utilizado na pesquisa do item, o qual pode ser: nome, descrição ou categoria.
	 * @param sortType
	 * 			O tipo de ordenação na qual os itens serão exibidos, a qual pode ser: crescente ou decrescente.
	 * @param sortCriteria
	 * 			O critério de como serão exibidos os itens, que pode ser: por data de criação do item
	 * 			ou por reputação do dono do item.
	 * @return
	 * 			Os itens encontrados na pesquisa.
	 * @throws Exception
	 * 			Lança uma exceção caso um dos parâmetros de entrada seja inválido.
	 */
	public String searchItem(String idSession, String keyWord, String attribute, String sortType, String sortCriteria) throws Exception{
		checkValidIdSession(idSession);
		
		if(keyWord == null || keyWord.equals(""))
			throw new Exception("Chave inválida");
		
		if(attribute == null || attribute.equals(""))
			throw new Exception("Atributo inválido");
		
		if(sortType == null || sortType.equals(""))
			throw new Exception("Tipo inválido de ordenação");
		
		if(sortCriteria == null || sortCriteria.equals(""))
			throw new Exception("Critério inválido de ordenação");
		
		if(!attribute.equals("nome") && !attribute.equals("descricao") && !attribute.equals("categoria")){
			throw new Exception("Atributo inexistente");
		}
		
		if(!sortType.equals("crescente") && !sortType.equals("decrescente")){
			throw new Exception("Tipo de ordenação inexistente");
		}
		
		if(!sortCriteria.equals("dataCriacao") && !sortCriteria.equals("reputacao")){
			throw new Exception("Critério de ordenação inexistente");
		}
		
		String itemFound = "";
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				if(sortCriteria.equals("dataCriacao")){
					for(User friend : user.getFriends()){
						if(friend.getMyRegisteredItems().size() == 0){
							itemFound = "";
						}
						// Crescente e Data de criação
						else{
							if(sortType.equals("crescente")){
								for(Item item : friend.getMyRegisteredItems()){
									if(attribute.equals("nome") && item.getName().toLowerCase().contains(keyWord)){
										itemFound += item.getName() + "; ";
									}
									else if(attribute.equals("descricao") && item.getDescription().toLowerCase().contains(keyWord)){
										itemFound += item.getName() + "; ";
									}
									else{
										if(item.getCategory().toLowerCase().contains(keyWord)){
											itemFound += item.getName() + "; ";
										}
									}
								}
							}
							// Decrescente e Data de criação
							else if(sortType.equals("decrescente")){
								for(int i = friend.getMyRegisteredItems().size()-1; i >= 0; i--){
									if(attribute.equals("nome") && friend.getMyRegisteredItems().get(i).getName().toLowerCase().contains(keyWord)){
										itemFound = friend.getMyRegisteredItems().get(i).getName() + "; " + itemFound;
									}
									else if(attribute.equals("descricao") && friend.getMyRegisteredItems().get(i).getDescription().toLowerCase().contains(keyWord)){
										itemFound = friend.getMyRegisteredItems().get(i).getName() + "; " + itemFound;
									}
									else{
										if(friend.getMyRegisteredItems().get(i).getCategory().toLowerCase().contains(keyWord)){
											itemFound = friend.getMyRegisteredItems().get(i).getName() + "; " + itemFound;
										}
									}
								}
							}
						}
					}
				}
				else{
					classifyUserFriends(user);
					// Crescente e Reputação
					for(User friend : reputationSort){
						if(sortType.equals("crescente")){
							for(Item item : friend.getMyRegisteredItems()){
								if(attribute.equals("nome") && item.getName().toLowerCase().contains(keyWord)){
									itemFound += item.getName() + "; ";
								}
								else if(attribute.equals("descricao") && item.getDescription().toLowerCase().contains(keyWord)){
									itemFound += item.getName() + "; ";
								}
								else{
									if(item.getCategory().toLowerCase().contains(keyWord)){
										itemFound += item.getName() + "; ";
									}
								}
							}
						}
						// Decrescente e Reputação
						else{
							for(int i = friend.getMyRegisteredItems().size()-1; i >= 0; i--){
								if(attribute.equals("nome") && friend.getMyRegisteredItems().get(i).getName().toLowerCase().contains(keyWord)){
									itemFound = friend.getMyRegisteredItems().get(i).getName() + "; " + itemFound;
								}
								else if(attribute.equals("descricao") && friend.getMyRegisteredItems().get(i).getDescription().toLowerCase().contains(keyWord)){
									itemFound = friend.getMyRegisteredItems().get(i).getName() + "; " + itemFound;
								}
								else{
									if(friend.getMyRegisteredItems().get(i).getCategory().toLowerCase().contains(keyWord)){
										itemFound = friend.getMyRegisteredItems().get(i).getName() + "; " + itemFound;
									}
								}
							}
						}
					}
				}
			}
		}
		
		if(itemFound.equals("")){
			return "Nenhum item encontrado";
		}
		return itemFound = itemFound.substring(0, itemFound.length() - 2);
	}
	
	/**
	 * Calcula a reputação de um usuário do sistema.
	 * 
	 * @param user
	 * 			O usuário o qual a reputação será calculada.
	 * @return
	 * 			A reputação do usuário.
	 * @throws Exception
	 * 			Lança uma exceção caso o usuário seja nulo.
	 */
	public int calculateReputation(User user) throws Exception{
		if(user == null){
			throw new Exception("Usuário inexistente");
		}
		
		int reputation = 0;
		
		for(Item item : user.getMyRegisteredItems()){
			if(borrowedItems.contains(item)){
				if(item.getStatus().equals("Completado")){
					reputation += 1;
				}
				else if(item.getStatus().equals("Cancelado")){
					reputation -= 1;
				}
			}
		}
		return reputation;
	}
	
	/**
	 * Classifica os amigos de um determinado usuário com base na reputação.
	 * 
	 * @param user
	 * 			O usuário do qual a reputação dos amigos será calculada.
	 */
	public void classifyUserFriends(User user){
		for(int i = 0; i < user.getFriends().size(); i++){
			if(reputationSort.size() == 0){
				reputationSort.add(user.getFriends().get(i));
			}
			else{
				for(int j = 0; j < reputationSort.size(); j++){
					if(user.getFriends().get(i).getReputation() < reputationSort.get(j).getReputation()){
						if(!reputationSort.contains(user.getFriends().get(i))){
							reputationSort.add(j, user.getFriends().get(i));
							break;
						}
					}
				}
			}
		}
	}
	
	/**
	 * Desfaz amizades entre usuários do sistema.
	 * 
	 * @param idSession
	 * 			O id da sessão do usuário logado no sistema.
	 * @param friend
	 * 			O amigo do qual a amizade será desfeita.
	 * @throws Exception
	 * 			Lança uma exceção caso um dos parâmetros de entrada seja inválido ou caso a amizade seja
	 * 			inexistente.
	 */
	public void undoFriendship(String idSession, String friend) throws Exception{
		checkValidIdSession(idSession);
		checkValidLogin(friend);
		checkNoUser(friend);
		
		int countFriend = 0;
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				for(User friendUser : user.getFriends()){
					if(friendUser.getLogin().equals(friend)){
						for(Item item : user.getMyRequestedItems()){
							if(item.getBorrower().equals(friendUser)){
								allLoanRequisitions.remove(item.getIdRequisition());
							}
						}
						user.getFriends().remove(friendUser);
						friendUser.getFriends().remove(user);
						countFriend += 1;
						break;
					}
				}
				if(countFriend == 0){
					throw new Exception("Amizade inexistente");
				}
			}
		}
	}
	
	/**
	 * Remove um item do sistema.
	 * 
	 * @param idSession
	 * 			O id da sessão do usuário logado no sistema.
	 * @param idItem
	 * 			O id do item a ser removido do sistema.
	 * @throws Exception
	 * 			Lança uma exceção caso um dos parâmetros de entrada seja inválido, ou caso o item esteja
	 * 			emprestado, ou o usuário logado não tenha permissão para remover o item do sistema ou caso
	 * 			o item seja inexistente.
	 */
	public void deleteItem(String idSession, String idItem) throws Exception{
		checkValidIdSession(idSession);
		
		if(idItem == null || idItem.equals("")){
			throw new Exception("Identificador do item é inválido");
		}
		
		if (!idItem.matches("^[0-9]*$"))
			throw new Exception("Item inexistente");
		
		int countID = 0;
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				for(Item item : registeredItems){
					if(item.getID().equals(idItem)){
						countID += 1;
						if(item.getOwner().equals(user)){
							if(!user.getMyBorrowedItems().contains(item)){
								
								for(String requisition : allLoanRequisitions){
									if(requisition.equals(item.getIdRequisition())){
										allLoanRequisitions.remove(requisition);
										break;
									}
								}
									
								user.getMyRegisteredItems().remove(item);
								registeredItems.remove(item);
								break;
							}
							else{
								throw new Exception("O usuário não pode apagar este item enquanto estiver emprestado");
							}
						}
						else{
							throw new Exception("O usuário não tem permissão para apagar este item");
						}
					}
				}
				if(countID == 0){
					throw new Exception("Item inexistente");
				}
			}
		}
	}
	
	/**
	 * Mostra o ranking dos usuários do sistema de acordo com a reputação de cada um.
	 * 
	 * @param idSession
	 * 			O id do usuário logado no sistema.
	 * @param category
	 * 			A categoria de exibição do ranking, que pode ser: global ou amigos.
	 * @return
	 * 			O ranking dos usuários do sistema.
	 * @throws Exception
	 * 			Lança uma exceção caso um dos parâmetros de entrada seja inválido.
	 */
	public String getRanking(String idSession, String category) throws Exception{
		checkValidIdSession(idSession);
		
		if(category == null || category.equals("")){
			throw new Exception("Categoria inválida");
		}
		
		if(!category.equals("global") && !category.equals("amigos")){
			throw new Exception("Categoria inexistente");
		}
		
		String ranking = "";
		
		rankingUsers();
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				if(category.equals("global")){
					for(User users : usersRanking){
						ranking += users.getLogin() + "; ";
					}
				}
				else{
					for(User users : usersRanking){
						if(user.getFriends().contains(users) || user.equals(users)){
							ranking += users.getLogin() + "; ";
						}
					}
				}
			}
		}
		return ranking = ranking.substring(0, ranking.length() - 2);
	}
	
	/**
	 * Organiza o ranking dos usuários de acordo com a reputação de cada um.
	 */
	public void rankingUsers(){
		for(User user : registeredUsers){
			if(usersRanking.size() == 0){
				usersRanking.add(user);
			}
			else{
				for(int i = 0; i < usersRanking.size(); i++){
					if(user.getReputation() > usersRanking.get(i).getReputation()){
						if(!usersRanking.contains(user)){
							usersRanking.add(i, user);
							break;
						}
					}
				}
			}
		}
	}
	
	/**
	 * Exibe o histórico de atividades dos usuários do sistema.
	 * 
	 * @param idSession
	 * 			O id da sessão do usuário logado no sistema.
	 * @return
	 * 			O histórico de atividades do usuário.
	 * @throws Exception
	 * 			Lança uma exceção caso a id da sessão do usuário seja inválida.
	 */
	public String historicOfActivities(String idSession) throws Exception{
		checkValidIdSession(idSession);
		
		String historic = "";
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				if(user.getMyHisotric().size() != 0){
					for(String historics : user.getMyHisotric()){
						historic += historics + "; ";
					}
				}
			}
		}
		
		if(historic.equals("")){
			return "Não há atividades";
		}
		
		return historic = historic.substring(0, historic.length() - 2);
		
	}
	
	/**
	 * Exibe o histórico de atividades de um grupo de usuários do sistema.
	 * 
	 * @param idSession
	 * 			O id da sessão do usuário logado no sistema.
	 * @return
	 * 			O histórico de atividades do grupo de usuários.
	 * @throws Exception
	 * 			Caso o id do usuário logado no sistema seja inválido.
	 */
	public String historicOfGroupActivities(String idSession) throws Exception{
		checkValidIdSession(idSession);
		
		String historic = "";
		
		for(User user : registeredUsers){
			if(checkUserSession(user).equals(idSession)){
				if(allHistoric.size() != 0){
					for(String[] historics : allHistoric){
						if(user.getLogin().equals(historics[1])){
							historic += historics[0] + "; ";
						}
					}
				}
			}
		}
		
		if(historic.equals("")){
			return "Não há atividades";
		}
		
		return historic = historic.substring(0, historic.length() - 2);
	}
}
